/src/wireshark/epan/dissectors/packet-eapol.c
Line | Count | Source |
1 | | /* packet-eapol.c |
2 | | * Routines for EAPOL and EAPOL-Key IEEE 802.1X-2010 PDU dissection |
3 | | * |
4 | | * Wireshark - Network traffic analyzer |
5 | | * By Gerald Combs <gerald@wireshark.org> |
6 | | * Copyright 1998 Gerald Combs |
7 | | * |
8 | | * SPDX-License-Identifier: GPL-2.0-or-later |
9 | | */ |
10 | | |
11 | | #include "config.h" |
12 | | |
13 | | #include <epan/packet.h> |
14 | | #include <epan/etypes.h> |
15 | | #include <epan/proto_data.h> |
16 | | #include <epan/tfs.h> |
17 | | |
18 | | #include "packet-eapol.h" |
19 | | |
20 | | void proto_register_eapol(void); |
21 | | void proto_reg_handoff_eapol(void); |
22 | | |
23 | | static int proto_eapol; |
24 | | static int hf_eapol_version; |
25 | | static int hf_eapol_type; |
26 | | static int hf_eapol_len; |
27 | | static int hf_eapol_keydes_type; |
28 | | static int hf_eapol_keydes_body; |
29 | | static int hf_eapol_keydes_key_len; |
30 | | static int hf_eapol_keydes_replay_counter; |
31 | | static int hf_eapol_keydes_key_iv; |
32 | | static int hf_eapol_keydes_key_index; |
33 | | static int hf_eapol_keydes_key_index_type; |
34 | | static int hf_eapol_keydes_key_index_number; |
35 | | static int hf_eapol_keydes_key_signature; |
36 | | static int hf_eapol_keydes_key; |
37 | | static int hf_eapol_keydes_key_generated_locally; |
38 | | |
39 | | static int ett_eapol; |
40 | | static int ett_eapol_key_index; |
41 | | static int ett_keyinfo; |
42 | | |
43 | | static dissector_table_t eapol_type_dissector_table; |
44 | | static dissector_table_t eapol_keydes_type_dissector_table; |
45 | | |
46 | | static dissector_handle_t eapol_handle; |
47 | | |
48 | 42 | #define EAPOL_HDR_LEN 4 |
49 | | |
50 | | #define EAPOL_2001 1 |
51 | | #define EAPOL_2004 2 |
52 | | #define EAPOL_2010 3 |
53 | | |
54 | | static const value_string eapol_version_vals[] = { |
55 | | { EAPOL_2001, "802.1X-2001" }, |
56 | | { EAPOL_2004, "802.1X-2004" }, |
57 | | { EAPOL_2010, "802.1X-2010" }, |
58 | | { 0, NULL } |
59 | | }; |
60 | | |
61 | | static const value_string eapol_type_vals[] = { |
62 | | { EAPOL_EAP, "EAP Packet" }, |
63 | | { EAPOL_START, "Start" }, |
64 | | { EAPOL_LOGOFF, "Logoff" }, |
65 | | { EAPOL_KEY, "Key" }, |
66 | | { EAPOL_ENCAP_ASF_ALERT, "Encapsulated ASF Alert" }, |
67 | | { EAPOL_MKA, "MKA" }, |
68 | | { EAPOL_ANNOUNCEMENT_GENERIC, "Announcement (Generic)" }, |
69 | | { EAPOL_ANNOUNCEMENT_SPECIFIC, "Announcement (Specific)" }, |
70 | | { EAPOL_ANNOUNCEMENT_REQUEST, "Announcement Request" }, |
71 | | { 0, NULL } |
72 | | }; |
73 | | |
74 | | static const value_string eapol_keydes_type_vals[] = { |
75 | | { EAPOL_RC4_KEY, "RC4 Descriptor" }, |
76 | | { EAPOL_RSN_KEY, "EAPOL RSN Key" }, |
77 | | { EAPOL_WPA_KEY, "EAPOL WPA Key" }, |
78 | | { 0, NULL } |
79 | | }; |
80 | | |
81 | | static const true_false_string keytype_tfs = { "Unicast", "Broadcast" }; |
82 | | |
83 | 16 | #define KEYDES_KEY_INDEX_TYPE_MASK 0x80 |
84 | 16 | #define KEYDES_KEY_INDEX_NUMBER_MASK 0x7F |
85 | | |
86 | | static int |
87 | | dissect_eapol(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) |
88 | 42 | { |
89 | 42 | int offset = 0; |
90 | 42 | uint8_t eapol_type; |
91 | 42 | uint16_t eapol_len; |
92 | 42 | unsigned len; |
93 | 42 | proto_tree *ti; |
94 | 42 | proto_tree *eapol_tree; |
95 | 42 | tvbuff_t *next_tvb; |
96 | | |
97 | 42 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "EAPOL"); |
98 | 42 | col_clear(pinfo->cinfo, COL_INFO); |
99 | | |
100 | 42 | ti = proto_tree_add_item(tree, proto_eapol, tvb, 0, -1, ENC_NA); |
101 | 42 | eapol_tree = proto_item_add_subtree(ti, ett_eapol); |
102 | | |
103 | 42 | proto_tree_add_item(eapol_tree, hf_eapol_version, tvb, offset, 1, ENC_BIG_ENDIAN); |
104 | 42 | offset++; |
105 | | |
106 | 42 | proto_tree_add_item_ret_uint8(eapol_tree, hf_eapol_type, tvb, offset, 1, ENC_BIG_ENDIAN, &eapol_type); |
107 | 42 | col_add_str(pinfo->cinfo, COL_INFO, |
108 | 42 | val_to_str(pinfo->pool, eapol_type, eapol_type_vals, "Unknown Type (0x%02X)")); |
109 | 42 | offset++; |
110 | | |
111 | 42 | eapol_len = tvb_get_ntohs(tvb, offset); |
112 | 42 | len = EAPOL_HDR_LEN + eapol_len; |
113 | 42 | set_actual_length(tvb, len); |
114 | 42 | if (tree) { |
115 | 41 | proto_item_set_len(ti, len); |
116 | 41 | proto_tree_add_item(eapol_tree, hf_eapol_len, tvb, offset, 2, ENC_BIG_ENDIAN); |
117 | 41 | } |
118 | 42 | offset += 2; |
119 | | |
120 | | /* Save eapol key type packets for IEEE 802.11 dissector and |
121 | | * MKA type packets for the MKA dissector */ |
122 | 42 | if (!pinfo->fd->visited && (eapol_type == EAPOL_KEY || eapol_type == EAPOL_MKA)) { |
123 | 1 | proto_eapol_key_frame_t *key_frame = wmem_new(pinfo->pool, proto_eapol_key_frame_t); |
124 | 1 | key_frame->type = 0; |
125 | 1 | key_frame->len = len; |
126 | 1 | key_frame->data = (uint8_t *)wmem_alloc(pinfo->pool, len); |
127 | 1 | tvb_memcpy(tvb, key_frame->data, 0, len); |
128 | 1 | p_add_proto_data(pinfo->pool, pinfo, proto_eapol, EAPOL_KEY_FRAME_KEY, key_frame); |
129 | 1 | } |
130 | | |
131 | 42 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
132 | 42 | if (!dissector_try_uint_with_data(eapol_type_dissector_table, |
133 | 42 | eapol_type, next_tvb, pinfo, tree, |
134 | 42 | false, eapol_tree)) { |
135 | 8 | call_data_dissector(next_tvb, pinfo, tree); |
136 | 8 | } |
137 | 42 | return tvb_captured_length(tvb); |
138 | 42 | } |
139 | | |
140 | | static int |
141 | | dissect_eapol_key(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void* data) |
142 | 0 | { |
143 | 0 | uint8_t keydesc_type; |
144 | 0 | int offset = 0; |
145 | 0 | tvbuff_t *next_tvb; |
146 | 0 | proto_tree* eapol_tree = (proto_tree*)data; |
147 | |
|
148 | 0 | keydesc_type = tvb_get_uint8(tvb, offset); |
149 | 0 | proto_tree_add_item(eapol_tree, hf_eapol_keydes_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
150 | 0 | offset += 1; |
151 | 0 | next_tvb = tvb_new_subset_remaining(tvb, offset); |
152 | | |
153 | | /* Save keydesc_type for IEEE 802.11 dissector */ |
154 | 0 | if (!pinfo->fd->visited) { |
155 | 0 | proto_eapol_key_frame_t *key_frame = (proto_eapol_key_frame_t *) |
156 | 0 | p_get_proto_data(pinfo->pool, pinfo, proto_eapol, EAPOL_KEY_FRAME_KEY); |
157 | 0 | if (key_frame) { |
158 | 0 | key_frame->type = keydesc_type; |
159 | 0 | } |
160 | 0 | } |
161 | |
|
162 | 0 | if (!dissector_try_uint_with_data(eapol_keydes_type_dissector_table, |
163 | 0 | keydesc_type, next_tvb, pinfo, eapol_tree, |
164 | 0 | false, NULL)) { |
165 | 0 | proto_tree_add_item(eapol_tree, hf_eapol_keydes_body, tvb, offset, -1, ENC_NA); |
166 | 0 | } |
167 | |
|
168 | 0 | return tvb_captured_length(tvb); |
169 | 0 | } |
170 | | |
171 | | static int |
172 | | dissect_eapol_rc4_key(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, void *data _U_) |
173 | 0 | { |
174 | 0 | int offset = 0; |
175 | 0 | uint16_t eapol_key_len; |
176 | 0 | bool generated_locally; |
177 | 0 | proto_tree *ti; |
178 | 0 | proto_tree *key_index_tree; |
179 | 0 | int eapol_len; |
180 | |
|
181 | 0 | proto_tree_add_item_ret_uint16(tree, hf_eapol_keydes_key_len, tvb, offset, 2, ENC_BIG_ENDIAN, &eapol_key_len); |
182 | 0 | offset += 2; |
183 | 0 | proto_tree_add_item(tree, hf_eapol_keydes_replay_counter, tvb, |
184 | 0 | offset, 8, ENC_BIG_ENDIAN); |
185 | 0 | offset += 8; |
186 | 0 | proto_tree_add_item(tree, hf_eapol_keydes_key_iv, tvb, |
187 | 0 | offset, 16, ENC_NA); |
188 | 0 | offset += 16; |
189 | 0 | ti = proto_tree_add_item(tree, hf_eapol_keydes_key_index, tvb, offset, 1, ENC_BIG_ENDIAN); |
190 | 0 | key_index_tree = proto_item_add_subtree(ti, ett_eapol_key_index); |
191 | 0 | proto_tree_add_item(key_index_tree, hf_eapol_keydes_key_index_type, |
192 | 0 | tvb, offset, 1, ENC_BIG_ENDIAN); |
193 | 0 | proto_tree_add_item(key_index_tree, hf_eapol_keydes_key_index_number, |
194 | 0 | tvb, offset, 1, ENC_BIG_ENDIAN); |
195 | 0 | offset += 1; |
196 | 0 | proto_tree_add_item(tree, hf_eapol_keydes_key_signature, tvb, |
197 | 0 | offset, 16, ENC_NA); |
198 | 0 | offset += 16; |
199 | 0 | if (eapol_key_len != 0) { |
200 | | /* |
201 | | * Body length of EAPOL-Key message in which we're contained is 1 byte |
202 | | * larger than the reported length of the key descriptor we were handed, |
203 | | * that 1 byte being the Key Descriptor Type. |
204 | | */ |
205 | 0 | eapol_len = 1 + tvb_reported_length(tvb); |
206 | | |
207 | | /* IEEE 802.1X-2004 7.6.3.6: If no bytes remain, then */ |
208 | 0 | generated_locally = eapol_len <= 44; /* Size of rc4 key with no key content */ |
209 | 0 | if (!generated_locally) { |
210 | 0 | proto_tree_add_item(tree, hf_eapol_keydes_key, tvb, offset, |
211 | 0 | eapol_key_len, ENC_NA); |
212 | 0 | } |
213 | |
|
214 | 0 | proto_tree_add_boolean(tree, hf_eapol_keydes_key_generated_locally, tvb, offset, |
215 | 0 | 0, generated_locally); |
216 | 0 | } |
217 | 0 | return tvb_captured_length(tvb); |
218 | 0 | } |
219 | | |
220 | | void |
221 | | proto_register_eapol(void) |
222 | 16 | { |
223 | 16 | static hf_register_info hf[] = { |
224 | 16 | { &hf_eapol_version, { |
225 | 16 | "Version", "eapol.version", |
226 | 16 | FT_UINT8, BASE_DEC, VALS(eapol_version_vals), 0x0, |
227 | 16 | NULL, HFILL }}, |
228 | | |
229 | 16 | { &hf_eapol_type, { |
230 | 16 | "Type", "eapol.type", |
231 | 16 | FT_UINT8, BASE_DEC, VALS(eapol_type_vals), 0x0, |
232 | 16 | NULL, HFILL }}, |
233 | | |
234 | 16 | { &hf_eapol_len, { |
235 | 16 | "Length", "eapol.len", |
236 | 16 | FT_UINT16, BASE_DEC, NULL, 0x0, |
237 | 16 | NULL, HFILL }}, |
238 | | |
239 | 16 | { &hf_eapol_keydes_type, { |
240 | 16 | "Key Descriptor Type", "eapol.keydes.type", |
241 | 16 | FT_UINT8, BASE_DEC, VALS(eapol_keydes_type_vals), 0x0, |
242 | 16 | NULL, HFILL }}, |
243 | | |
244 | 16 | { &hf_eapol_keydes_body, { |
245 | 16 | "Key Descriptor Body", "eapol.keydes.body", |
246 | 16 | FT_BYTES, BASE_NONE, NULL, 0x0, |
247 | 16 | NULL, HFILL }}, |
248 | | |
249 | 16 | { &hf_eapol_keydes_key_len, { |
250 | 16 | "Key Length", "eapol.keydes.key_len", |
251 | 16 | FT_UINT16, BASE_DEC, NULL, 0x0, |
252 | 16 | NULL, HFILL }}, |
253 | | |
254 | 16 | { &hf_eapol_keydes_replay_counter, { |
255 | 16 | "Replay Counter", "eapol.keydes.replay_counter", |
256 | 16 | FT_UINT64, BASE_DEC, NULL, 0x0, |
257 | 16 | NULL, HFILL }}, |
258 | | |
259 | 16 | { &hf_eapol_keydes_key_iv, { |
260 | 16 | "Key IV", "eapol.keydes.key_iv", |
261 | 16 | FT_BYTES, BASE_NONE, NULL, 0x0, |
262 | 16 | NULL, HFILL }}, |
263 | | |
264 | 16 | { &hf_eapol_keydes_key_index, { |
265 | 16 | "Key Index", "eapol.keydes.key_index", |
266 | 16 | FT_UINT8, BASE_HEX, NULL, 0x0, |
267 | 16 | NULL, HFILL }}, |
268 | | |
269 | 16 | { &hf_eapol_keydes_key_index_type, { |
270 | 16 | "Type", "eapol.keydes.key_index.type", |
271 | 16 | FT_BOOLEAN, 8, TFS(&keytype_tfs), KEYDES_KEY_INDEX_TYPE_MASK , |
272 | 16 | NULL, HFILL }}, |
273 | | |
274 | 16 | { &hf_eapol_keydes_key_index_number, { |
275 | 16 | "Number", "eapol.keydes.key_index.number", |
276 | 16 | FT_UINT8, BASE_DEC, NULL, KEYDES_KEY_INDEX_NUMBER_MASK, |
277 | 16 | NULL, HFILL }}, |
278 | | |
279 | 16 | { &hf_eapol_keydes_key_signature, { |
280 | 16 | "Key Signature", "eapol.keydes.key_signature", |
281 | 16 | FT_BYTES, BASE_NONE, NULL, 0x0, |
282 | 16 | NULL, HFILL }}, |
283 | | |
284 | 16 | { &hf_eapol_keydes_key, { |
285 | 16 | "Key", "eapol.keydes.key", |
286 | 16 | FT_BYTES, BASE_NONE, NULL, 0x0, |
287 | 16 | NULL, HFILL }}, |
288 | | |
289 | 16 | { &hf_eapol_keydes_key_generated_locally, { |
290 | 16 | "Key Generated Locally", "eapol.keydes.key.generated_locally", |
291 | 16 | FT_BOOLEAN, BASE_NONE, NULL, 0x0, |
292 | 16 | NULL, HFILL }}, |
293 | 16 | }; |
294 | | |
295 | 16 | static int *ett[] = { |
296 | 16 | &ett_eapol, |
297 | 16 | &ett_keyinfo, |
298 | 16 | &ett_eapol_key_index |
299 | 16 | }; |
300 | | |
301 | 16 | proto_eapol = proto_register_protocol("802.1X Authentication", "EAPOL", "eapol"); |
302 | 16 | eapol_handle = register_dissector("eapol", dissect_eapol, proto_eapol); |
303 | | |
304 | 16 | proto_register_field_array(proto_eapol, hf, array_length(hf)); |
305 | 16 | proto_register_subtree_array(ett, array_length(ett)); |
306 | | |
307 | 16 | eapol_type_dissector_table = register_dissector_table("eapol.type", |
308 | 16 | "EAPOL Packet Type", |
309 | 16 | proto_eapol, FT_UINT8, |
310 | 16 | BASE_DEC); |
311 | 16 | eapol_keydes_type_dissector_table = register_dissector_table("eapol.keydes.type", |
312 | 16 | "EAPOL Key Descriptor Type", |
313 | 16 | proto_eapol, FT_UINT8, |
314 | 16 | BASE_DEC); |
315 | 16 | } |
316 | | |
317 | | void |
318 | | proto_reg_handoff_eapol(void) |
319 | 16 | { |
320 | 16 | dissector_handle_t eapol_rc4_key_handle, eapol_key_handle; |
321 | | |
322 | 16 | dissector_add_uint("ethertype", ETHERTYPE_EAPOL, eapol_handle); |
323 | 16 | dissector_add_uint("ethertype", ETHERTYPE_RSN_PREAUTH, eapol_handle); |
324 | | |
325 | | /* |
326 | | * EAPOL key descriptor types. |
327 | | */ |
328 | 16 | eapol_rc4_key_handle = create_dissector_handle(dissect_eapol_rc4_key, proto_eapol); |
329 | 16 | dissector_add_uint("eapol.keydes.type", EAPOL_RC4_KEY, eapol_rc4_key_handle); |
330 | 16 | eapol_key_handle = create_dissector_handle(dissect_eapol_key, proto_eapol); |
331 | 16 | dissector_add_uint("eapol.type", EAPOL_KEY, eapol_key_handle); |
332 | 16 | } |
333 | | |
334 | | /* |
335 | | * Editor modelines |
336 | | * |
337 | | * Local Variables: |
338 | | * c-basic-offset: 2 |
339 | | * tab-width: 8 |
340 | | * indent-tabs-mode: nil |
341 | | * End: |
342 | | * |
343 | | * ex: set shiftwidth=2 tabstop=8 expandtab: |
344 | | * :indentSize=2:tabSize=8:noTabs=true: |
345 | | */ |