wlan_rsn/key/exchange/
mod.rs1pub mod handshake;
6
7use self::handshake::fourway::{self, Fourway};
8use self::handshake::group_key::{self, GroupKey};
9use crate::Error;
10use crate::key::gtk::Gtk;
11use crate::key::igtk::Igtk;
12use crate::key::ptk::Ptk;
13use crate::rsna::{Dot11VerifiedKeyFrame, NegotiatedProtection, UpdateSink};
14use zerocopy::SplitByteSlice;
15
16#[derive(Debug, Clone, PartialEq)]
17pub enum Key {
18 Pmk(Vec<u8>),
19 Ptk(Ptk),
20 Gtk(Gtk),
21 Igtk(Igtk),
22 MicRx(Vec<u8>),
23 MicTx(Vec<u8>),
24 Smk(Vec<u8>),
25 Stk(Vec<u8>),
26}
27
28impl Key {
29 pub fn name(&self) -> &'static str {
30 match self {
31 Key::Pmk(..) => "PMK",
32 Key::Ptk(..) => "PTK",
33 Key::Gtk(..) => "GTK",
34 Key::Igtk(..) => "IGTK",
35 Key::MicRx(..) => "MIC_RX",
36 Key::MicTx(..) => "MIC_TX",
37 Key::Smk(..) => "SMK",
38 Key::Stk(..) => "STK",
39 }
40 }
41}
42
43#[derive(Debug, PartialEq)]
44pub enum Method {
45 FourWayHandshake(Box<Fourway>),
46 GroupKeyHandshake(GroupKey),
47}
48
49impl Method {
50 #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
51 pub fn on_eapol_key_frame<B: SplitByteSlice>(
52 &mut self,
53 update_sink: &mut UpdateSink,
54 frame: Dot11VerifiedKeyFrame<B>,
55 ) -> Result<(), Error> {
56 match self {
57 Method::FourWayHandshake(hs) => hs.on_eapol_key_frame(update_sink, frame),
58 Method::GroupKeyHandshake(hs) => hs.on_eapol_key_frame(update_sink, frame),
59 }
60 }
61
62 #[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
63 pub fn on_rsna_response_timeout(&self) -> Result<(), Error> {
64 match self {
65 Method::FourWayHandshake(hs) => hs.on_rsna_response_timeout(),
66 _ => Ok(()),
68 }
69 }
70
71 pub fn destroy(self) -> Config {
72 match self {
73 Method::FourWayHandshake(hs) => (*hs).destroy(),
74 Method::GroupKeyHandshake(hs) => hs.destroy(),
75 }
76 }
77}
78
79#[derive(Clone, Debug, PartialEq)]
80pub enum Config {
81 FourWayHandshake(fourway::Config),
82 GroupKeyHandshake(group_key::Config),
83}
84
85#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
86pub fn compute_mic_from_buf(
89 kck: &[u8],
90 protection: &NegotiatedProtection,
91 frame: &[u8],
92) -> Result<Vec<u8>, Error> {
93 let integrity_alg = protection.integrity_algorithm()?;
94 let mic_len = protection.akm.mic_bytes().ok_or(Error::UnsupportedAkmSuite)? as usize;
95 let mut mic = integrity_alg.compute(kck, frame)?;
96 mic.truncate(mic_len);
97 Ok(mic)
98}
99
100#[allow(clippy::result_large_err, reason = "mass allow for https://fxbug.dev/381896734")]
101pub fn compute_mic<B: SplitByteSlice>(
106 kck: &[u8],
107 protection: &NegotiatedProtection,
108 frame: &eapol::KeyFrameRx<B>,
109) -> Result<Vec<u8>, Error> {
110 let integrity_alg = protection.integrity_algorithm()?;
111 let mic_len = protection.akm.mic_bytes().ok_or(Error::UnsupportedAkmSuite)? as usize;
112 if !frame.key_frame_fields.key_info().key_mic() {
113 return Err(Error::ComputingMicForUnprotectedFrame);
114 }
115 if frame.key_mic.len() != mic_len {
116 return Err(Error::MicSizesDiffer(frame.key_mic.len(), mic_len));
117 }
118
119 let buf = frame.to_bytes(true);
120 let mut mic = integrity_alg.compute(kck, &buf[..])?;
121 mic.truncate(mic_len);
122 Ok(mic)
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128 use crate::integrity::{self, Algorithm};
129 use crate::rsna::test_util;
130 use assert_matches::assert_matches;
131 use wlan_common::ie::rsn::akm::Akm;
132
133 fn fake_key_frame(mic_len: usize) -> eapol::KeyFrameTx {
134 let key_info = eapol::KeyInformation(0).with_key_mic(true);
135 eapol::KeyFrameTx::new(
136 eapol::ProtocolVersion::IEEE802DOT1X2010,
137 eapol::KeyFrameFields::new(
138 eapol::KeyDescriptor::IEEE802DOT11,
139 key_info,
140 16,
141 0,
142 [0u8; 32],
143 [0u8; 16],
144 0,
145 ),
146 vec![],
147 mic_len,
148 )
149 }
150
151 #[test]
152 fn compute_mic_unknown_akm() {
153 const KCK: [u8; 16] = [5; 16];
154 let frame = fake_key_frame(16)
155 .serialize()
156 .finalize_with_mic(&[0u8; 16][..])
157 .expect("failed to create fake key frame");
158 let mut protection = test_util::get_rsne_protection();
159 protection.akm = Akm::new_dot11(200);
160 let result = compute_mic(&KCK[..], &protection, &frame.keyframe());
161 assert_matches!(result, Err(Error::UnknownIntegrityAlgorithm));
162 }
163
164 #[test]
165 fn compute_mic_bit_not_set() {
166 const KCK: [u8; 16] = [5; 16];
167 let mut frame = fake_key_frame(16);
168 frame.key_frame_fields.set_key_info(eapol::KeyInformation(0));
169 let frame =
170 frame.serialize().finalize_without_mic().expect("failed to create fake key frame");
171 let result = compute_mic(&KCK[..], &test_util::get_rsne_protection(), &frame.keyframe());
172 assert_matches!(result, Err(Error::ComputingMicForUnprotectedFrame));
173 }
174
175 #[test]
176 fn compute_mic_different_mic_sizes() {
177 const KCK: [u8; 16] = [5; 16];
178 let frame = fake_key_frame(0)
179 .serialize()
180 .finalize_with_mic(&[][..])
181 .expect("failed to create fake key frame");
182 let result = compute_mic(&KCK[..], &test_util::get_rsne_protection(), &frame.keyframe());
183 assert_matches!(result, Err(Error::MicSizesDiffer(0, 16)));
184 }
185
186 #[test]
187 fn compute_mic_success() {
188 const KCK: [u8; 16] = [5; 16];
189 let frame = fake_key_frame(16)
190 .serialize()
191 .finalize_with_mic(&[0u8; 16][..])
192 .expect("failed to create fake key frame");
193 let mic = compute_mic(&KCK[..], &test_util::get_rsne_protection(), &frame.keyframe())
194 .expect("expected failure with unsupported AKM");
195 assert!(integrity::hmac_sha1::HmacSha1::new().verify(&KCK[..], &frame[..], &mic[..]));
196 }
197}