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